#include "SJF.h"
#include "linkedList.h"
#include <sys/times.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
// jobNode *job = pointer to the job(s) that not yet enqueue
// jobNode *ready = pointer to the head of the ready queue
// clock_t = start cpu clock tick
// psjf = set to 1 to enalbe PSJF mode
// alarm_policy = alarm interval (sec)

void sjf(struct jobNode **ready, struct jobNode **job, clock_t start, int psjf, int *alarm_policy) {

    //struct jobNode *temp_job;
    //struct jobNode *temp_ready_pre = NULL;
    struct jobNode *pre_sort_head = NULL;
    struct jobNode *pre = NULL;
    struct jobNode *temp = NULL;
    clock_t end;
    struct tms tmsend;
    static long clktck = 0;
    //int dirtybit = 0;
    //temp_job = job;
    //temp_ready = *ready;
    temp = *ready;

    if (psjf == 1)
        pre_sort_head = *ready;

    // handle sigchld case


    end = times(&tmsend);

    //get system clock tick per second
    if (clktck == 0)
            if ((clktck = sysconf(_SC_CLK_TCK)) < 0) {
                perror("sysconf error");
                exit(-1);
            }

    if (psjf == 0) {
        if (*ready != NULL && (*ready)->timeRemain == 0) {
            printf("dequeue\n");
            temp = *ready;
            *ready = (*ready)->ready_next;
            temp->ready_next = NULL;
        }
    } else {
        if (*ready != NULL && (*ready)->ptimeRemain == 0) {
            printf("dequeue\n");
            temp = *ready;
            *ready = (*ready)->ready_next;
            temp->ready_next = NULL;
        }
    }
    // enqueue the ready job into the ready queue
    //while(job != NULL) {
        // job arrivaled
        while (*job != NULL && (*job)->arrivalTime <= (int)((end-start)/clktck)) {
            pre = NULL;
            // find the correct position to insert the job to the ready queue
            if (*ready == NULL) { // no job in the ready queue at the begining
                *ready = *job;
                temp = *ready;
                *job = (*job)->next; // job already added.
            } else {        // there are job(s) inside the ready queue
                    temp = *ready; // save the location of the head of the ready queue
                    while(1) {
                        if ((*job)->runinfinity == 1){
                            while((*ready)->ready_next != NULL)
                                *ready = (*ready)->ready_next;
                            (*ready)->ready_next = *job;
                            *job = (*job)->next;
                            break;
                        } else {
                            if ((*ready)->runinfinity == 1){
                                (*job)->ready_next = *ready;
                            	if(pre == NULL) // head of the ready queue, update to new head
                            	    temp = *job;
                                else
                                    pre->ready_next = *job;
                                //*ready = *job;
                            	*job = (*job)->next;
                            	break;
                            } else {
                                if(psjf == 0) {
                                    if ((*ready)->timeRemain > (*job)->timeRemain) {
                                        (*job)->ready_next = *ready;
                                        if(pre == NULL) // head of the ready queue, update to new head
                                            temp = *job;
                                        else
                                            pre->ready_next = *job;
                                        //*ready = *job;
                                        *job = (*job)->next;
                                        break;
                                    } else {
                                        if((*ready)->ready_next != NULL){
                                            pre = *ready;
                                            *ready = (*ready)->ready_next;
                                        } else {
                                            (*ready)->ready_next = *job;
                                            (*job)->ready_next = NULL;
                                            *job = (*job)->next;
                                            break;
                                        }
                                    }
                                } else {
                                    if ((*ready)->ptimeRemain > (*job)->ptimeRemain) {
                                        (*job)->ready_next = *ready;
                                        if(pre == NULL) // head of the ready queue, update to new head
                                            temp = *job;
                                        else
                                            pre->ready_next = *job;
                                        //*ready = *job;
                                        *job = (*job)->next;
                                        break;
                                    } else {
                                        if((*ready)->ready_next != NULL){
                                            pre = *ready;
                                            *ready = (*ready)->ready_next;
                                        } else {
                                            (*ready)->ready_next = *job;
                                            (*job)->ready_next = NULL;
                                            *job = (*job)->next;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                *ready = temp;
        }

    //=======SIGTSTP possible runnint pre_sort_head process==========
    //if (psjf == 1 && pre_sort_head != NULL && *ready!= NULL && pre_sort_head->child_pid > 0 && pre_sort_head != *ready) {
    //	if(kill(pre_sort_head->child_pid,SIGTSTP) == -1)
    	//printf("SJF SIGTSTP\n");
    	//{
        //    perror("SIGTSTP ");
        //    exit(-1);
       // }
    	//pre_sort_head->timeline[pre_sort_head->timelineIndex][1] = (float)(end - start)/(float)clktck;
    	//(pre_sort_head->timelineIndex)++;
    //}
    //===============================================================



 if (psjf == 1)
        	*alarm_policy = 1;  // PSJF mode
 else
            if(*ready != NULL){
                if ((*ready)->runinfinity == 1)
                    *alarm_policy = 1;
                else
                    *alarm_policy = (*ready)->timeRemain; // should be integer only , SJF mode ONLY
            }
}
